package org.biodas.jdas.client;

import org.apache.log4j.Logger;
import org.biodas.jdas.client.adapters.features.DasGFFAdapter;
import org.biodas.jdas.exceptions.DASClientException;
import org.biodas.jdas.schema.features.DASGFF;
import org.springframework.http.*;
import org.springframework.web.client.HttpClientErrorException;
import org.springframework.web.client.RestTemplate;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;

import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.List;


/**
 * @author Leyla Garcia
 *
 */
public class FeaturesClient implements FeaturesClientInterface {	
	
	RestTemplate restTemp = new RestTemplate();
	
	private static Logger logger = Logger.getLogger(FeaturesClient.class);

   ConnectionPropertyProviderI connectionProps = null;
 
   public FeaturesClient()
   {
   }
 
   public FeaturesClient(ConnectionPropertyProviderI connProps) {
     this.connectionProps = connProps;
   }
 
    /**
     * Fetches data from a source with the arguments provided, which should correspond to a DAS query string starting with ?.
     * @param serverURL Source URL
     * @param arguments DAS query string starting with ?
     * @return DASGFF element
     * @throws DASClientException
     */
    public DasGFFAdapter fetchData(String serverURL, String arguments) throws DASClientException {	
            if (!serverURL.endsWith("/")) {
                serverURL += "/";
            }
			
            String url = serverURL + "features" + arguments;
            logger.debug("url="+url);
            NoDtdJaxbParser parser=new NoDtdJaxbParser();
			
			try {
				return new DasGFFAdapter((DASGFF)parser.parseXmlUrl(url,"org.biodas.jdas.schema.features",connectionProps));
			} catch (IOException e) {
				// TODO Auto-generated catch block
				throw new DASClientException(e.getMessage(), e.getCause());
			} catch (JAXBException e) {
				throw new DASClientException(e.getMessage(), e.getCause());
			}
			
		
	}

    /**
     * @see org.biodas.jdas.client.FeaturesClientInterface#fetchData(java.lang.String, java.util.List)
     * @param serverURL
     * @param segments
     * @return
     * @throws DASClientException
     */
    @Override
	public DasGFFAdapter fetchData(String serverURL, List<String> segments) throws DASClientException {
			return fetchData(serverURL, segments, null, null, null, null, null);
		
    }

    /**
     * @see org.biodas.jdas.client.FeaturesClientInterface#fetchDataWithTypes(java.lang.String, java.util.List, java.util.List)
     * @param serverURL
     * @param segments
     * @param types
     * @return
     * @throws DASClientException
     */
    @Override
	public DasGFFAdapter fetchDataWithTypes(String serverURL, List<String> segments, List<String>types) throws DASClientException {
        return fetchData(serverURL, segments, types, null, null, null, null);
    }

    /**
     * @see org.biodas.jdas.client.FeaturesClientInterface#fetchDataWithFeatueIds(java.lang.String, java.util.List, java.util.List)
     * @param serverURL
     * @param segments
     * @param featureIds
     * @return
     * @throws DASClientException
     */
    @Override
	public DasGFFAdapter fetchDataWithFeatueIds(String serverURL, List<String> segments, List<String> featureIds) throws DASClientException {
        return fetchData(serverURL, segments, null, null, null, featureIds, null);
    }

    /**
     * @see org.biodas.jdas.client.FeaturesClientInterface#fetchData(java.lang.String, java.util.List, java.util.List, java.util.List, java.lang.String, java.util.List, java.lang.String)
     * @param serverURL
     * @param segments
     * @param types
     * @param categories
     * @param categorize
     * @param featureIds
     * @param maxbins
     * @return
     * @throws DASClientException
     */
	@Override
	public DasGFFAdapter fetchData(String serverURL, List<String> segments, List<String> types
            , List<String> categories, String categorize, List<String> featureIds, String maxbins) throws DASClientException {

        String segmentArguments = null;
        if ((segments != null) && (segments.size() != 0)) {
            segmentArguments= "";
            for (String segment: segments) {
                segmentArguments += ";segment=" + segment;
            }
            segmentArguments = segmentArguments.substring(1); //we need to remove the first ;
        }

        String typeArguments = null;
        if ((types != null) && (types.size() != 0)) {
            typeArguments = "";
            for (String type: types) {
                typeArguments += ";type=" + type;
            }
            typeArguments = typeArguments.substring(1); //we need to remove the first ;
        }

        String categoryArguments = null;
        if ((categories != null) && (categories.size() != 0)) {
            categoryArguments = "";
            for (String category: categories) {
                categoryArguments += ";category=" + category;
            }
            categoryArguments = categoryArguments.substring(1); //we need to remove the first ;
        }

        String featureIdArguments = null;
        if(featureIds!=null){
            if ((featureIds.size() != 0)) {
                featureIdArguments = "";
                for (String featureId: featureIds) {
                    featureIdArguments += ";feature_id=" + featureId;
                }
                featureIdArguments = featureIdArguments.substring(1); //we need to remove the first ;
            }
        }

        String arguments = null;
        if (segmentArguments != null) {
            arguments = segmentArguments;
        }
        if (typeArguments != null) {
            arguments = arguments == null ? typeArguments : arguments + ";" + typeArguments;
        }
        if (categoryArguments != null) {
            arguments = arguments == null ? categoryArguments : arguments + ";" + categoryArguments;
        }
        if (featureIdArguments != null) {
            arguments = arguments == null ? featureIdArguments : arguments + ";" + featureIdArguments;
        }
        if (categorize != null) {
            arguments = arguments == null ? "categorize=" + categorize : arguments + ";categorize=" + categorize;
        }
        if (maxbins != null) {
            arguments = arguments == null ? "maxbins=" + maxbins :  arguments + ";maxbins=" + maxbins;
        }
        arguments = arguments == null ? "" : "?" + arguments;

        return this.fetchData(serverURL, arguments);
	}

    /**
     *
     * @param url
     * @param dasgff
     * @param user
     * @param pass
     * @return
     * @throws DASClientException
     */
	public DasGFFAdapter postFeatures(String url, DasGFFAdapter dasgff, String user, String pass) throws DASClientException{
		HttpHeaders headers = new HttpHeaders();
		headers.setContentType(MediaType.APPLICATION_XML);
		
		HttpEntity<String> entity = new HttpEntity(dasgff, headers);

		ResponseEntity<DASGFF> responseBody = null;
		try {
			responseBody = restTemp.exchange(url,
					HttpMethod.POST, entity, DASGFF.class);
		} catch (HttpClientErrorException e) {
			throw new DASClientException(e.getMessage(), e.getCause());
		}	
		logger.info(responseBody.getStatusCode());
        if (!"201".equals(responseBody.getStatusCode().toString())) {
            throw new DASClientException("The response HTML code is not 201");
        }
		DasGFFAdapter featuresCreated = new DasGFFAdapter(responseBody.getBody());
		return new DasGFFAdapter(featuresCreated);
	}

}
